/**
 * useImperativeHandle
 *
 *    是什么：用于函数组件，处理函数组件对外暴露的内容。类比于 Vue3 中 defineExpose 或 expose 选项
 *
 *    怎么用：需要结合 forwardRef() 转发
 *
 *    语法：
 *        useImperativeHandle(ref对象, 函数返回内容)
 *          1. ref对象 - 转发时获取的 ref对象
 *          2. 函数返回内容 - 返回的内容就是对外暴露的东西，也就是 ref对象.current 获取到的东西
 *
 *
 *    案例：
 *      1. 实现一个 MySwiper 组件，父组件调用该组件时，可以获取到该组件的一些方法来控制 轮播图上一页和下一页
 *      2. 实现一个 Form 组件，父组件调用该组件时，可以通过 validate() 来校验表单
 *
 */

import {
  forwardRef,
  useEffect,
  useImperativeHandle,
  useRef,
  useState,
} from "react";
import Swiper from "swiper";
import "swiper/css";

const MySwiper = forwardRef(function (props, ref) {
  const selfSwiper = useRef();

  useImperativeHandle(ref, () => {
    return {
      name: "张三",
      age: 18,
      prev: () => {
        console.log("MySwiper 对外的 prev");
        // 操作 swiper 实例的 slidePrev()
        selfSwiper.current.slidePrev();
      },
      next: () => {
        console.log("MySwiper 对外的 next");
        // 操作 swiper 实例的 slideNext()
        selfSwiper.current.slideNext();
      },
    };
  });

  useEffect(() => {
    // 挂载完成，做Swiper的实例化
    selfSwiper.current = new Swiper(".swiper"); // PS：这儿的 .swiper 不可取
  }, []);

  return (
    <div className="swiper">
      <div className="swiper-wrapper">
        <div className="swiper-slide">Slide 1</div>
        <div className="swiper-slide">Slide 2</div>
        <div className="swiper-slide">Slide 3</div>
      </div>
    </div>
  );
});

const Form = forwardRef(function (props, ref) {
  useImperativeHandle(ref, () => {
    return {
      validate: () => {
        return new Promise((resolve, reject) => {
          console.log("Form 对外暴露的校验方法");
          // 将我的所有字段都做一番校验
          try {
            handleValidateTwo("username", model.username);
            resolve(model);
          } catch (error) {
            reject(error);
          }
        });
      },
    };
  });

  console.log("Form props", props);
  const { model, rules, setModel } = props;

  function handleChange(key, event) {
    console.log("key", key);
    console.log("value", event.target.value);

    // 调用 setModal 修改数据
    setModel({
      [key]: event.target.value,
    });
  }

  // 处理校验，校验具体的字段
  function handleValidate(key, event) {
    // value
    const value = event.target.value;
    // 基于 rules 取出 对应 key 的规则
    const rule = rules[key]; // []
    console.log("规则 rule", rule);
    // 循环 rule 一条一条规则去校验
    for (let i = 0; i < rule.length; i++) {
      const curRule = rule[i];
      if (curRule.required) {
        // 表示要校验数据是否必须存在
        if (!model[key]) {
          // 校验失败
          console.error("校验失败", curRule.message);
          break;
        }
      }
    }
  }

  function handleValidateTwo(key, value) {
    // 取出规则
    const rule = rules[key]; // []
    // 循环规则,去判断规则是否通过
    for (let i = 0; i < rule.length; i++) {
      const curRule = rule[i];
      if (curRule.required) {
        if (!value) {
          // 规则不通过
          throw new Error(curRule.message);
        }
      }
    }
  }

  return (
    <form>
      <label>
        <span>用户名：</span>
        <input
          type="text"
          placeholder="请输入用户名"
          value={model.username}
          onChange={(event) => handleChange("username", event)}
          onBlur={(event) => handleValidateTwo("username", event.target.value)}
        />
      </label>
    </form>
  );
});

function App() {
  const myRef = useRef();
  const myForm = useRef();

  const [model, setModel] = useState({
    username: "",
  });

  // 如果一个数据不是state数据，就直接定义即可。不需要使用useState
  const rules = {
    username: [
      {
        required: true,
        message: "请输入用户名",
      },
    ],
  };

  function onPrev() {
    console.log("App myRef", myRef);

    myRef.current.prev();
  }

  function onNext() {
    myRef.current.next();
  }

  function onSubmit() {
    // 调用 Form 校验方式
    myForm.current
      .validate()
      .then(() => {
        console.log("校验通过");
      })
      .catch((error) => {
        console.log("校验不通过", error);
      });
  }

  return (
    <div>
      <h1>App</h1>
      <button onClick={onPrev}>Prev</button>
      <button onClick={onNext}>Next</button>
      <hr />
      <MySwiper ref={myRef} />
      <hr />
      <Form ref={myForm} model={model} rules={rules} setModel={setModel} />
      {/* 提交按钮点击,需要控制 Form 组件,走一遍校验流程 */}
      <button onClick={onSubmit}>提交</button>
    </div>
  );
}

export default App;
